package com.dhp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dhp.Utils.AIUtil;
import com.dhp.Utils.ExcelUtil;
import com.dhp.Utils.UploadUtil;
import com.dhp.annotation.RateLimit;
import com.dhp.common.ErrorCode;
import com.dhp.constant.CommonConstant;
import com.dhp.constant.GenChartConstant;
import com.dhp.constant.MQConstant;
import com.dhp.constant.UserConstant;
import com.dhp.exception.BusinessException;
import com.dhp.mapper.chartMapper;
import com.dhp.model.dto.chart.ChartGenRequest;
import com.dhp.model.dto.chart.ChartQueryRequest;
import com.dhp.model.entity.Chart;
import com.dhp.model.entity.ChartData;
import com.dhp.model.entity.User;
import com.dhp.model.enums.GenChartStatusEnum;
import com.dhp.model.vo.GenChartVO;
import com.dhp.mq.MyMessageProducer;
import com.dhp.service.ChartDataService;
import com.dhp.service.ChartService;
import com.dhp.service.UserService;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
* @author dhp
*/
@Service
public class ChartServiceImpl extends ServiceImpl<chartMapper, Chart>
    implements ChartService {

    @Autowired
    private UserService userService;

    @Autowired
    private AIUtil aiUtil;

    @Autowired
    private ChartDataService chartDataService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Resource
    private MyMessageProducer messageProducer;
    @Override
    public void validChart(Chart chart, boolean add) {
        if (chart == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String name = chart.getName();
        String chartData = chart.getChartData();
        String chartType = chart.getChartType();
        String goal = chart.getGoal();
        // 创建时，所有参数必须非空
        if (add) {
            if (StringUtils.isAnyBlank(chartData,chartType,goal,name)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
        }
    }

    @Override
    public Page<Chart> listchartByPage(ChartQueryRequest chartQueryRequest, HttpServletRequest request) {
        Chart chartQuery = new Chart();
        BeanUtils.copyProperties(chartQueryRequest, chartQuery);
        long current = chartQueryRequest.getCurrent();
        long size = chartQueryRequest.getPageSize();

        String sortField = chartQueryRequest.getSortField();
        String sortOrder = chartQueryRequest.getSortOrder();
        String chartData = chartQuery.getChartData();
        String chartType = chartQuery.getChartType();
        Long userId = chartQuery.getUserId();
        String goal = chartQuery.getGoal();
        // content 需支持模糊搜索
        chartQuery.setChartData(null);
        chartQuery.setChartData(null);
        chartQuery.setGoal(null);
        chartQuery.setUserId(null);

        // 限制爬虫
        if (size > 50) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<Chart> queryWrapper = new QueryWrapper<>(chartQuery);
        queryWrapper.like(StringUtils.isNotBlank(chartData), "chartData", chartData);
        queryWrapper.like(StringUtils.isNotBlank(chartType), "chartType", chartType);
        queryWrapper.like(StringUtils.isNotBlank(goal), "goal", goal);
        queryWrapper.like(StringUtils.isNotBlank(goal), "userId", userId);
        queryWrapper.orderBy(StringUtils.isNotBlank(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC), sortField);
        Page<Chart> chartPage = this.page(new Page<>(current, size), queryWrapper);
        return chartPage;
    }

    @Override
    @RateLimit(key = "genChartByAI" , value = 5L , duration = 1)
    @Transactional
    public GenChartVO genChartByAI(MultipartFile file, ChartGenRequest chartGenRequest , HttpServletRequest request) {
        //校验文件是否符合要求
        boolean b = UploadUtil.CheckFile(file);
        if (b){
            throw new BusinessException(ErrorCode.OPERATION_ERROR , "文件格式不正确或文件太大");
        }

        // 获取压缩后的提问
        String fileData = ExcelUtil.excelToCsv(file);
        //获取AI完整的回答
        StringBuilder userRequest = new StringBuilder();
        if (!StrUtil.isAllNotEmpty(chartGenRequest.getChartType() , chartGenRequest.getGoal())){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        //将文件内容与与创建表单信息拼接 即用户问AI的输入
        userRequest.append("分析目标:" + chartGenRequest.getGoal()).append('\n');
        userRequest.append("结果图表类型:" + chartGenRequest.getChartType()).append('\n');
        userRequest.append("数据" + "\n");
        userRequest.append(fileData);
        String finalRequest = userRequest.toString();

        String fullAns = aiUtil.doChat(finalRequest);
        if (StringUtils.isEmpty(fullAns)){
            throw new BusinessException(ErrorCode.OPERATION_ERROR , "分析失败");
        }

        //将回答拆分
        String[] split = fullAns.split(GenChartConstant.AI_CHART_SPILT);
        String genResult = split[2];
        String genChart = split[1];

        //将数据存储到数据库
        Chart chart = new Chart();
        if (!StrUtil.isAllNotEmpty(genChart , genResult)){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        long userId = userService.getLoginUser(request).getId();
        BeanUtil.copyProperties(chartGenRequest , chart);
        chart.setUserId(userId);
        chart.setGenChart(genChart);
        chart.setGenResult(genResult);
        chart.setStatus(GenChartStatusEnum.SUCCEED.getValue());
        this.save(chart);

        //将表单的数据单独存放
        ChartData chartData = new ChartData();
        chartData.setChartId(chart.getId());
        chartData.setChartData(fileData);
        chartDataService.save(chartData);

        //更新redis
        Gson gson = new Gson();
        String key = UserConstant.CHART_KEY_PRE + userService.getLoginUser(request).getId();
        QueryWrapper<Chart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId" , userId);
        List<Chart> list = this.list(queryWrapper);
        String JsonStr = gson.toJson(list);
        redisTemplate.opsForValue().set(key , JsonStr);

        //构造返回数据
        GenChartVO genChartVO = new GenChartVO();
        BeanUtil.copyProperties(chart , genChartVO);
        genChartVO.setChartId(chart.getId());

        return genChartVO;
    }

    @Override
    @RateLimit(key = "genChartByAI" , value = 5L , duration = 1)
    @Transactional
    public GenChartVO genChartByAIAsync(MultipartFile file, ChartGenRequest chartGenRequest, HttpServletRequest request) {
        //校验文件是否符合要求
        boolean b = UploadUtil.CheckFile(file);
        if (b){
            throw new BusinessException(ErrorCode.OPERATION_ERROR , "文件格式不正确或文件太大");
        }
        // 获取压缩后的提问
        String fileData = ExcelUtil.excelToCsv(file);

        // 直接将当前的数据存入数据库
        Chart firstChart = new Chart();
        BeanUtil.copyProperties(chartGenRequest , firstChart);
        firstChart.setUserId(userService.getLoginUser(request).getId());
        firstChart.setStatus(GenChartStatusEnum.WAIT.getValue());
        this.save(firstChart);

        //表单数据单独存放
        ChartData chartData = new ChartData();
        chartData.setChartId(firstChart.getId());
        chartData.setChartData(fileData);
        chartDataService.save(chartData);

        //将获取的chartId当做消息发送
        Long charId = firstChart.getId();
        User cur = userService.getById(firstChart.getUserId());
        if (cur.getUserRole().equals(UserConstant.VIP_USER)) {
            messageProducer.sendMessage(MQConstant.EXCHANGE_NAME, MQConstant.ROUTING_KEY, charId.toString());
        }else {
            //转发给普通队列
            messageProducer.sendMessage(MQConstant.EXCHANGE_NAME, MQConstant.COMMON_ROUTING_KEY, charId.toString());
        }


        Chart finalChart = this.getById(charId);
        //构造返回数据
        GenChartVO genChartVO = new GenChartVO();
        BeanUtil.copyProperties(finalChart , genChartVO);
        genChartVO.setChartId(finalChart.getId());

        return genChartVO;
    }

    @Override
    public Page<Chart> listMyChart(ChartQueryRequest chartQueryRequest, HttpServletRequest request) {
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        Long userId = loginUser.getId();
        String name = chartQueryRequest.getName();

        //如果没有模糊查询的请求，则先查询redis中有没有
        if (StrUtil.isEmpty(name)){
            //如果redis中有则直接返回
            String key = UserConstant.CHART_KEY_PRE + userId;
            String JsonStr = redisTemplate.opsForValue().get(key);
            if (StrUtil.isNotEmpty(JsonStr) && !"[]".equals(JsonStr)){
                Gson gson = new Gson();
                List<Chart> list = gson.fromJson(JsonStr , new TypeToken<List<Chart>>(){}.getType());
                if (list == null) {
                    throw new BusinessException(ErrorCode.OPERATION_ERROR);
                }
                Page<Chart> page = new Page<>(chartQueryRequest.getCurrent() , chartQueryRequest.getPageSize());
                page.setTotal(list.size());
                page.setRecords(list);
                return page;
            }
        }

        //查询图表信息
        QueryWrapper<Chart> queryWrapper = new QueryWrapper<>();
        //支持根据名称模糊查询
        if (StrUtil.isNotEmpty(name)){
            queryWrapper.like("name" , name);
        }
        queryWrapper.eq("userId" , userId);
        Page<Chart> page = new Page<>(chartQueryRequest.getCurrent() , chartQueryRequest.getPageSize());
        Page<Chart> chartPage = this.page(page, queryWrapper);

        //将数据存入redis
        Gson gson = new Gson();
        String key = UserConstant.CHART_KEY_PRE + userId;
        //将自己的图标信息存入redis
        List<Chart> list = this.list(queryWrapper);
        String json = gson.toJson(list);
        redisTemplate.opsForValue().set(key , json);

        if (chartPage == null){
            throw new BusinessException(ErrorCode.OPERATION_ERROR , "请求失败");
        }

        return page;

    }


    @Override
    public String getUserInput(Chart chart , ChartData chartData){
        StringBuilder stringBuilder = new StringBuilder();
        String fileData = chartData.getChartData();
        if (!StrUtil.isAllNotEmpty(fileData , chart.getChartType() , chart.getGoal())){
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        //将文件内容与与创建表单信息拼接 即用户问AI的输入
        stringBuilder.append("分析目标:" + chart.getGoal()).append('\n');
        stringBuilder.append("结果图表类型:" + chart.getChartType()).append('\n');
        stringBuilder.append("数据:" + '\n');
        stringBuilder.append(fileData);

        return stringBuilder.toString();
    }


}




